package com.zl.tby.core.base.util;

import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;

/**
 * @author changpeng
 * @since 2025/10/30 18:47
 */
public class NetworkImageThumbnailGenerator {
    // 网络超时设置（毫秒）
    private static final int CONNECT_TIMEOUT = 5000;
    private static final int READ_TIMEOUT = 10000;
    // 支持的图片格式
    private static final String[] SUPPORTED_FORMATS = {"jpg", "jpeg", "png"};

    /**
     * 生成网络图片的等比缩略图
     * @param imageUrl 网络图片URL（JPG/PNG/JPEG）
     * @param destPath 缩略图保存路径
     * @param maxWidth 最大宽度（等比缩放）
     * @param maxHeight 最大高度（等比缩放）
     * @param quality 质量（0.0~1.0，仅对JPG有效）
     * @throws IOException 处理异常
     */
    public static void generateThumbnail(String imageUrl, String destPath, int maxWidth, int maxHeight, float quality) throws IOException {
        // 1. 验证URL格式
        if (!isValidUrl(imageUrl)) {
            throw new IllegalArgumentException("无效的图片URL: " + imageUrl);
        }

        // 2. 下载网络图片到临时文件
        File tempFile = downloadToTempFile(imageUrl);
        try {
            // 3. 提取文件格式（确保是支持的格式）
            String format = getFileFormat(tempFile, imageUrl);
            if (!isSupportedFormat(format)) {
                throw new IOException("不支持的图片格式: " + format);
            }

            // 4. 处理临时文件生成缩略图
            processLargeImage(tempFile, destPath, maxWidth, maxHeight, format, quality);
        } finally {
            // 5. 清理临时文件
            if (tempFile.exists() && !tempFile.delete()) {
                tempFile.deleteOnExit();
            }
        }
    }

    /**
     * 验证URL有效性
     */
    private static boolean isValidUrl(String url) {
        try {
            new URL(url);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 下载网络图片到临时文件
     */
    private static File downloadToTempFile(String imageUrl) throws IOException {
        URL url = new URL(imageUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // 配置HTTP请求（避免403）
        connection.setConnectTimeout(CONNECT_TIMEOUT);
        connection.setReadTimeout(READ_TIMEOUT);
        connection.setRequestMethod("GET");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36");
        connection.setRequestProperty("Accept", "image/jpeg,image/png,image/*");

        // 处理HTTP响应
        int responseCode = connection.getResponseCode();
        if (responseCode != HttpURLConnection.HTTP_OK) {
            throw new IOException("下载失败，响应码: " + responseCode + "，URL: " + imageUrl);
        }

        // 流式写入临时文件
        try (InputStream in = connection.getInputStream()) {
            File tempFile = File.createTempFile("net_thumb_", "." + getFileSuffix(imageUrl));
            tempFile.deleteOnExit(); // 程序退出时自动删除

            try (OutputStream out = new FileOutputStream(tempFile)) {
                byte[] buffer = new byte[8192]; // 8KB缓冲区，减少IO次数
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }
            return tempFile;
        } finally {
            connection.disconnect();
        }
    }

    /**
     * 提取文件后缀（用于临时文件）
     */
    private static String getFileSuffix(String url) {
        if (url.contains(".")) {
            String suffix = url.substring(url.lastIndexOf(".") + 1).toLowerCase();
            // 去除URL参数（如 "image.jpg?w=1000" -> "jpg"）
            if (suffix.contains("?") || suffix.contains("&")) {
                suffix = suffix.split("[?&]")[0];
            }
            return suffix;
        }
        return "jpg"; // 默认
    }

    /**
     * 确定图片实际格式（避免URL后缀与真实格式不符）
     */
    private static String getFileFormat(File tempFile, String url) throws IOException {
        // 尝试通过ImageIO识别真实格式
        try (ImageInputStream iis = ImageIO.createImageInputStream(tempFile)) {
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            if (readers.hasNext()) {
                String format = readers.next().getFormatName().toLowerCase();
                return "jpeg".equals(format) ? "jpg" : format; // 统一jpeg为jpg
            }
        }
        // 识别失败时 fallback 到URL后缀
        return getFileSuffix(url);
    }

    /**
     * 检查是否为支持的格式
     */
    private static boolean isSupportedFormat(String format) {
        for (String supported : SUPPORTED_FORMATS) {
            if (supported.equalsIgnoreCase(format)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 处理大图片生成缩略图（核心逻辑）
     */
    private static void processLargeImage(File srcFile, String destPath, int maxWidth, int maxHeight, String format, float quality) throws IOException {
        // 获取图片读取器
        ImageReader reader = getImageReader(srcFile, format);
        if (reader == null) {
            throw new IOException("不支持的图片格式: " + format);
        }

        try (ImageInputStream iis = ImageIO.createImageInputStream(srcFile)) {
            reader.setInput(iis, true, true); // 只读取元数据，不加载全图

            // 1. 获取原图宽高
            int originalWidth = reader.getWidth(0);
            int originalHeight = reader.getHeight(0);

            // 2. 计算等比缩放后的尺寸
            int[] targetSize = calculateTargetSize(originalWidth, originalHeight, maxWidth, maxHeight);
            int targetWidth = targetSize[0];
            int targetHeight = targetSize[1];

            // 3. 计算采样率（降低内存占用）
            int xSample = (int) Math.ceil((double) originalWidth / targetWidth);
            int ySample = (int) Math.ceil((double) originalHeight / targetHeight);
            xSample = Math.max(xSample, 1);
            ySample = Math.max(ySample, 1);

            // 4. 采样读取图片（只加载缩略图所需像素）
            ImageReadParam param = reader.getDefaultReadParam();
            param.setSourceSubsampling(xSample, ySample, 0, 0); // 间隔采样
            BufferedImage sampledImage = reader.read(0, param);

            // 5. 微调尺寸（确保精确匹配目标大小）
            BufferedImage thumbnail = resizeImage(sampledImage, targetWidth, targetHeight, format);

            // 6. 输出图片（控制质量）
            writeImage(thumbnail, destPath, format, quality);
        } finally {
            reader.dispose(); // 释放资源
        }
    }

    /**
     * 计算等比缩放尺寸
     */
    private static int[] calculateTargetSize(int originalWidth, int originalHeight, int maxWidth, int maxHeight) {
        if (originalWidth <= maxWidth && originalHeight <= maxHeight) {
            return new int[]{originalWidth, originalHeight}; // 无需缩放
        }
        // 取最小缩放比例，避免拉伸
        double scale = Math.min(
                (double) maxWidth / originalWidth,
                (double) maxHeight / originalHeight
        );
        return new int[]{
                (int) Math.round(originalWidth * scale),
                (int) Math.round(originalHeight * scale)
        };
    }

    /**
     * 调整图片尺寸（高质量缩放）
     */
    private static BufferedImage resizeImage(BufferedImage src, int targetWidth, int targetHeight, String format) {
        // 对于PNG保留透明通道，JPG用RGB
        int imageType = "png".equalsIgnoreCase(format)
                ? BufferedImage.TYPE_INT_ARGB
                : BufferedImage.TYPE_INT_RGB;

        BufferedImage dest = new BufferedImage(targetWidth, targetHeight, imageType);
        Graphics2D g = dest.createGraphics();

        // 高质量缩放配置
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);

        // 绘制缩放后的图片
        g.drawImage(src, 0, 0, targetWidth, targetHeight, null);
        g.dispose();
        return dest;
    }

    /**
     * 写入图片文件（控制质量）
     */
    private static void writeImage(BufferedImage image, String destPath, String format, float quality) throws IOException {
        File destFile = new File(destPath);
        // 确保目标目录存在
        File parentDir = destFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(format);
        if (!writers.hasNext()) {
            throw new IOException("找不到对应的图片写入器: " + format);
        }

        ImageWriter writer = writers.next();
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(destFile)) {
            writer.setOutput(ios);

            // 配置压缩参数（仅对JPG有效）
            ImageWriteParam param = writer.getDefaultWriteParam();
            if (param.canWriteCompressed() && "jpg".equalsIgnoreCase(format)) {
                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                param.setCompressionQuality(quality); // 0.0最低，1.0最高
            }

            writer.write(null, new IIOImage(image, null, null), param);
        } finally {
            writer.dispose();
        }
    }

    /**
     * 获取图片读取器
     */
    private static ImageReader getImageReader(File file, String format) throws IOException {
        try (ImageInputStream iis = ImageIO.createImageInputStream(file)) {
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(format);
            if (readers.hasNext()) {
                return readers.next();
            }
            // 尝试通过文件内容自动识别
            readers = ImageIO.getImageReaders(iis);
            return readers.hasNext() ? readers.next() : null;
        }
    }


    // 测试
    public static void main(String[] args) {
        try {
            // 示例：处理网络JPG/PNG图片
            generateThumbnail(
                    "http://172.20.1.6:12007/file/files/2025/1/21/10/iRz3q8V428qj9xTQWEil-.jpg",
                    "D:/aaa/650x300.jpg", 650, 300, 0.8f
            );
            System.out.println("缩略图生成成功！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
